package com.zzvcom.doc.paper;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.docx4j.convert.out.html.HtmlCssHelper;
import org.docx4j.dml.wordprocessingDrawing.Inline;
import org.docx4j.model.styles.StyleTree;
import org.docx4j.model.styles.Tree;
import org.docx4j.openpackaging.packages.WordprocessingMLPackage;
import org.docx4j.openpackaging.parts.Part;
import org.docx4j.openpackaging.parts.PartName;
import org.docx4j.openpackaging.parts.WordprocessingML.BinaryPart;
import org.docx4j.openpackaging.parts.WordprocessingML.MainDocumentPart;
import org.docx4j.relationships.Relationship;
import org.docx4j.wml.*;

import javax.xml.bind.JAXBElement;
import java.io.File;
import java.util.Base64;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 试卷解析器，演示尝试
 * 目前发现styleId老有变动，所以我使用了
 * 样式名称来判断
 */
public class ExamParser {

    private ObjectMapper mapper = new ObjectMapper();

    public static void main(String[] args) throws Exception {
        ExamParser parser = new ExamParser();
        String jsonResult = parser.parseExamDocument("doc/exam_template1.docx");
        System.out.println(jsonResult);
    }

    /**
     * 解析试卷文档并转换为JSON格式
     *
     * @param filePath Word文档路径
     * @return JSON字符串
     */
    public String parseExamDocument(String filePath) throws Exception {
        WordprocessingMLPackage wordMLPackage = WordprocessingMLPackage.load(new File(filePath));
        MainDocumentPart mainPart = wordMLPackage.getMainDocumentPart();
        StyleTree styleTree = mainPart.getStyleTree();
        Tree<StyleTree.AugmentedStyle> paragraphStylesTree = styleTree.getParagraphStylesTree();
        Map<String, Style> pStyleMap = new HashMap<>();
        paragraphStylesTree.toList().forEach(n -> {
            StyleTree.AugmentedStyle style = n.getData();
            Style s = style.getStyle();
            String styleId = s.getStyleId();

            pStyleMap.put(styleId, s);
        });


        ObjectNode examJson = mapper.createObjectNode();
        ArrayNode questionsArray = mapper.createArrayNode();

        List<Object> paragraphs = mainPart.getContent();
        String examTitle = "";
        int questionIndex = 0;

        for (int i = 0; i < paragraphs.size(); i++) {
            Object obj = paragraphs.get(i);

            if (obj instanceof P) {
                P paragraph = (P) obj;
                String styleId = getParagraphStyleId(paragraph);
                String text = getParagraphHtml(paragraph, wordMLPackage);

                if (isExamTitle(pStyleMap, styleId)) {
                    examTitle = text;
                    examJson.put("title", examTitle);
                } else if (isExamQuestion(pStyleMap, styleId)) {
                    // 检查是否是题目标题（如"一、选择题"）
                    if (text.matches(".*[一二三四五六七八九十]、.*")) {
                        // 题型标题，跳过处理
                        continue;
                    }

                    // 创建新题目
                    ObjectNode question = mapper.createObjectNode();
                    questionIndex++;
                    question.put("id", questionIndex);
                    question.put("type", "single_choice"); // 默认为单选题
                    question.put("stem", text);

                    // 解析选项
                    ArrayNode optionsArray = mapper.createArrayNode();
                    i = parseOptions(paragraphs, i + 1, optionsArray, wordMLPackage, pStyleMap);
                    question.set("options", optionsArray);

                    // 查找答案
                    if (i + 1 < paragraphs.size() && paragraphs.get(i + 1) instanceof P) {
                        P nextParagraph = (P) paragraphs.get(i + 1);
                        String nextStyleId = getParagraphStyleId(nextParagraph);
                        String nextText = getParagrapText(nextParagraph, wordMLPackage);

                        if (isExamAnswer(pStyleMap, nextStyleId)) {
                            question.put("answer", nextText.substring(3)); // 去掉"答案："前缀
                            i++; // 跳过答案段落
                        }
                    }

                    questionsArray.add(question);
                }
            }
        }

        examJson.set("questions", questionsArray);
        return mapper.writerWithDefaultPrettyPrinter().writeValueAsString(examJson);
    }

    private String getParagrapText(P paragraph, WordprocessingMLPackage wordMLPackage) {

        List<Object> runs = paragraph.getContent();
        StringBuilder texts=new StringBuilder();
        for (Object obj : runs) {
            if (obj instanceof R) {
                R run = (R) obj;
                List<Object> runContent = run.getContent();
                for (Object contentObj : runContent) {
                    if (contentObj instanceof JAXBElement) {
                        JAXBElement jaxbElement = (JAXBElement) contentObj;
                        if (jaxbElement.getValue() instanceof Text) {
                            Text t = (Text) jaxbElement.getValue();
                            texts.append(t.getValue());
                        } else if (contentObj instanceof Text) {
                            Text t = (Text) contentObj;
                            texts.append(t.getValue());
                        }
                    }
                }

            }
        }
            return texts.toString();
        }

    private boolean isExamAnswer(Map<String, Style> pStyleMap, String nextStyleId) {
        return isEqualsStyleName(pStyleMap, nextStyleId, "试卷答案");
    }

    private boolean isExamOption(Map<String, Style> pStyleMap, String styleId) {
        return isEqualsStyleName(pStyleMap, styleId,"试卷选项");
    }
    private boolean isExamQuestion(Map<String, Style> pStyleMap, String styleId) {

        return isEqualsStyleName(pStyleMap, styleId,"试卷题目");
    }

    private boolean isExamTitle(Map<String, Style> pStyleMap, String styleId) {
        return isEqualsStyleName(pStyleMap, styleId,"试卷标题");

    }

    private static boolean isEqualsStyleName(Map<String, Style> pStyleMap, String styleId, String styleName) {
        Style style = pStyleMap.get(styleId);
        if (style == null){
            return false;
        }
        Style.Name name = style.getName();
        if (name == null){
            return false;
        }
        String val = name.getVal();
        return styleName.equals(val);
    }

    /**
     * 解析选项部分
     */
    private int parseOptions(List<Object> paragraphs, int startIndex, ArrayNode optionsArray,
                             WordprocessingMLPackage wordMLPackage, Map<String, Style> pStyleMap) throws Exception {
        int i = startIndex;

        while (i < paragraphs.size()) {
            Object obj = paragraphs.get(i);

            if (obj instanceof P) {
                P paragraph = (P) obj;
                String styleId = getParagraphStyleId(paragraph);

                // 如果遇到下一个题目或答案，停止解析选项
                if (isExamQuestion(pStyleMap,styleId) || isExamAnswer(pStyleMap,styleId)) {
                    break;
                }

                // 如果是选项样式
                if (isExamOption(pStyleMap,styleId)) {
                    ObjectNode option = mapper.createObjectNode();
                    String optionText = getParagraphHtml(paragraph, wordMLPackage);

                    // 提取选项标识（A、B、C、D等）
                    if (optionText.length() > 0 && optionText.charAt(0) >= 'A' && optionText.charAt(0) <= 'Z') {
                        option.put("label", String.valueOf(optionText.charAt(0)));
                        // 提取选项内容（去掉"A. "前缀）
                        if (optionText.length() > 2 && optionText.charAt(1) == '.') {
                            option.put("content", optionText.substring(3));
                        } else {
                            option.put("content", optionText.substring(1));
                        }
                    } else {
                        option.put("label", "");
                        option.put("content", optionText);
                    }

                    optionsArray.add(option);
                }

                // 检查是否有图片
                List<Object> drawingObjects = paragraph.getContent();
                for (Object contentObj : drawingObjects) {
                    if (contentObj instanceof R) {
                        R run = (R) contentObj;
                        List<Object> runContent = run.getContent();
                        for (Object runObj : runContent) {
                            if (runObj instanceof Drawing) {
                                Drawing drawing = (Drawing) runObj;
                                String imageHtml = extractImageAsHtml(drawing, wordMLPackage);
                                if (!imageHtml.isEmpty() && optionsArray.size() > 0) {
                                    // 将图片添加到最后一个选项中
                                    ObjectNode lastOption = (ObjectNode) optionsArray.get(optionsArray.size() - 1);
                                    lastOption.put("content", lastOption.get("content").asText() + imageHtml);
                                }
                            }
                        }
                    }
                }
            } else {
                // 遇到非段落对象，停止解析选项
                break;
            }

            i++;
        }

        return i - 1; // 返回最后一个处理的索引
    }


    /**
     * 获取段落的样式ID
     */
    private String getParagraphStyleId(P paragraph) {
        PPr pPr = paragraph.getPPr();
        if (pPr != null && pPr.getPStyle() != null) {
            return pPr.getPStyle().getVal();
        }
        return "";
    }

    /**
     * 获取段落文本内容
     */
    /**
     * 获取段落文本内容并转换为带HTML样式的文本
     */
    private String getParagraphHtml(P paragraph, WordprocessingMLPackage wordMLPackage) {
        StringBuilder htmlText = new StringBuilder();
        List<Object> runs = paragraph.getContent();

        StringBuilder pCssText = new StringBuilder();
        if (paragraph.getPPr() != null) {
            HtmlCssHelper.createCss(wordMLPackage, paragraph.getPPr(), pCssText, true, false);
        }
        if(pCssText.length()==0){
            htmlText.append("<p>");
        }else{
            htmlText.append("<p style=\"" + pCssText + "\">");
        }

        for (Object obj : runs) {
            if (obj instanceof R) {
                R run = (R) obj;
                StringBuilder runCssText = new StringBuilder();
                if (run.getRPr() != null) {
                    HtmlCssHelper.createCss(wordMLPackage, run.getRPr(), runCssText);
                }
                htmlText.append(getRunText(run, runCssText));
            }
        }
        htmlText.append("</p>");

        return htmlText.toString();
    }

    /**
     * 获取运行(Run)中的文本内容
     */
    private String getRunText(R run,   StringBuilder runCssText) {
        StringBuilder text = new StringBuilder();
        List<Object> runContent = run.getContent();
        for (Object contentObj : runContent) {
            if (contentObj instanceof JAXBElement) {
                JAXBElement jaxbElement = (JAXBElement) contentObj;
                if (jaxbElement.getValue() instanceof Text) {
                    Text t = (Text) jaxbElement.getValue();
                    if(runCssText.length()>0) {
                        text.append("<span style=\"" + runCssText + "\">");
                    }else if(runCssText.length()==0){
                        text.append("<span>");
                    }
                    text.append(t.getValue());
                    text.append("</span>");

                } else if (jaxbElement.getValue() instanceof R.Tab) {
                    text.append("\t");
                } else if (jaxbElement.getValue() instanceof Br) {
                    text.append("<br/>");
                }
            } else if (contentObj instanceof Text) {
                Text t = (Text) contentObj;
                if(runCssText.length()>0) {
                    text.append("<span style=\"" + runCssText + "\">");
                }else if(runCssText.length()==0){
                    text.append("<span>");
                }
                text.append(t.getValue());
                text.append("</span>");

            } else if (contentObj instanceof R.Tab) {
                text.append("\t");
            } else if (contentObj instanceof Br) {
                text.append("<br/>");
            }
        }

        return text.toString();
    }
    /**
     * 提取图片并转换为HTML img标签
     */
    private String extractImageAsHtml(Drawing drawing, WordprocessingMLPackage wordMLPackage) {
        try {
            List<Object> anchorOrInline = drawing.getAnchorOrInline();
            if (!anchorOrInline.isEmpty()) {
                Object anchorInline = anchorOrInline.get(0);
                if (anchorInline instanceof Inline) {
                    Inline inline = (Inline) anchorInline;
                    String id = inline.getDocPr().getId() + "";

                    // 生成base64图片数据
                    String base64Image = extractImageBase64(id, wordMLPackage);
                    if (!base64Image.isEmpty()) {
                        return "<img src=\"data:image/png;base64," + base64Image + "\" alt=\"选项图片\" />";
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return "";
    }

    /**
     * 提取图片的base64编码数据
     */
    private String extractImageBase64(String id, WordprocessingMLPackage wordMLPackage) {
        try {
            Map<PartName, Part> parts = wordMLPackage.getParts().getParts();
            for (Map.Entry<PartName, Part> entry : parts.entrySet()) {
                PartName partName = entry.getKey();

                if (partName.getName().contains("media/image") &&
                        partName.getName().contains("." + id + ".")) {
                    Part part = entry.getValue();
                    System.out.println("partName: " + partName.getName());
                    Relationship rel = part.getRelationshipsPart().getRelationshipByID(id);
                    Part part1 = part.getRelationshipsPart().getPart(rel);
                    if (part1 instanceof BinaryPart) {
                        BinaryPart binaryPart = (BinaryPart) part1;
                        byte[] imageBytes = binaryPart.getBytes();
                        return Base64.getEncoder().encodeToString(imageBytes);
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return "";
    }
}
